﻿using AMS.Common.ToolChains.Extensions;
using System.Text;

namespace AMS.Common.ToolChains.xxHash;

public static class AssetsSerialNumberGenerator
{
    public static string Generate(string mask)
    {
        var xx64 = new XXH64();

        var buffer = BitConverter.GetBytes(DateTime.UtcNow.Ticks);

        xx64.Update(buffer.AsSpan());

        var uniqueCode = Convert.ToBase64String(xx64.DigestBytes());

        return $"{Disorder(PurifyCode(uniqueCode).ToUpper(), mask.ToUpper())}";
    }

    private static string PurifyCode(string origin)
    {
        var sb = new StringBuilder(origin);

        for (var i = 0; i < sb.Length; i++)
        {
            if (IsSymbolCharacter(sb[i]))
            {
                sb[i] = GetRandomCharacter();
            }
        }

        return sb.ToString();
    }

    private static string Disorder(string origin, string mask)
    {
        var enu = Slice(origin.Length, mask.Length);

        mask = mask.Disorder();

        var sb = new StringBuilder(origin);

        for (var i = 0; i < enu.Count; i++)
        {
            sb.Insert(enu[i], mask[i]);
        }

        return sb.ToString();
    }

    private static bool IsSymbolCharacter(char target)
    {
        return target is (>= (char)32 and < (char)48) or
            (>= (char)58 and <= (char)64) or
            (>= (char)91 and <= (char)96) or
            (>= (char)123 and <= (char)126);
    }

    private static char GetRandomCharacter()
    {
        var firstDoor = Random.Shared.Next(0, 2);

        return firstDoor switch
        {
            0 => (char)Random.Shared.Next(48, 57),
            1 => (char)Random.Shared.Next(65, 90),
            2 => (char)Random.Shared.Next(97, 122),
            _ => 'X',
        };
    }

    private static List<int> Slice(int length, int chuckCount)
    {
        var flag = length / chuckCount;

        var slices = Enumerable.Repeat(0, chuckCount).ToList();
        slices[0] = Random.Shared.Next(1, flag);

        for (var i = 1; i < slices.Count; i++)
        {
            var seed = Random.Shared.Next(1, flag);
            slices[i] += slices[i - 1] + (i * seed);
        }

        return slices;
    }
}